#!/usr/bin/env python3
"""
Seasoning Store Management System.

Features
--------
- Track employee identity/contact info and performance targets.
- Automatically calculate payroll based on performance outcomes.
- Track product inventory, expiry dates, and low-stock thresholds.
- Provide expiry warnings and stock alerts.
- Simple CLI to interact with the in-memory store state.
"""

from __future__ import annotations

import json
from dataclasses import dataclass, asdict
from datetime import datetime, timedelta
from pathlib import Path
from typing import Dict, List, Optional


DATA_FILE = Path("seasoning_store_data.json")
EXPIRY_WARNING_DAYS = 14


def _now() -> datetime:
    return datetime.now()


def _parse_date(value: str) -> datetime:
    return datetime.strptime(value, "%Y-%m-%d")


def _format_date(value: datetime) -> str:
    return value.strftime("%Y-%m-%d")


@dataclass
class Employee:
    employee_id: str
    name: str
    role: str
    contact: str
    base_salary: float
    performance_target: float
    performance_score: float = 0.0
    guarantor_name: str = ""  # 担保人姓名
    guarantor_contact: str = ""  # 担保人联系方式
    guarantor_relation: str = ""  # 担保人关系

    def salary(self) -> float:
        """Calculate salary with performance multiplier."""
        if self.performance_target <= 0:
            return self.base_salary
        multiplier = min(self.performance_score / self.performance_target, 1.5)
        return round(self.base_salary * (0.7 + 0.3 * multiplier), 2)


@dataclass
class Product:
    sku: str
    name: str
    category: str
    quantity: int
    reorder_threshold: int
    expires_on: datetime
    price: float = 200.0  # 产品单价，默认200元

    def to_dict(self) -> Dict:
        data = asdict(self)
        data["expires_on"] = _format_date(self.expires_on)
        return data

    @staticmethod
    def from_dict(data: Dict) -> "Product":
        data = dict(data)
        data["expires_on"] = _parse_date(data["expires_on"])
        # 向后兼容：如果旧数据没有price字段，使用默认值200
        if "price" not in data:
            data["price"] = 200.0
        return Product(**data)

    def needs_restock(self) -> bool:
        return self.quantity <= self.reorder_threshold

    def needs_expiry_warning(self) -> bool:
        return self.expires_on <= _now() + timedelta(days=EXPIRY_WARNING_DAYS)


@dataclass
class SaleRecord:
    sale_id: str
    sku: str
    product_name: str
    quantity: int
    employee_id: Optional[str]
    sale_date: datetime
    revenue: float  # 销售金额（数量 * 单价，这里用固定单价200）

    def to_dict(self) -> Dict:
        data = asdict(self)
        data["sale_date"] = _format_date(self.sale_date)
        return data

    @staticmethod
    def from_dict(data: Dict) -> "SaleRecord":
        data = dict(data)
        data["sale_date"] = _parse_date(data["sale_date"])
        return SaleRecord(**data)


class StoreDatabase:
    def __init__(self, path: Path) -> None:
        self.path = path
        self.employees: Dict[str, Employee] = {}
        self.products: Dict[str, Product] = {}
        self.sales_history: List[SaleRecord] = []
        self.load()

    def load(self) -> None:
        if not self.path.exists():
            self._seed_defaults()
            return
        data = json.loads(self.path.read_text(encoding="utf-8"))
        self.employees = {
            item["employee_id"]: Employee(**item) for item in data.get("employees", [])
        }
        self.products = {
            item["sku"]: Product.from_dict(item) for item in data.get("products", [])
        }
        self.sales_history = [
            SaleRecord.from_dict(item) for item in data.get("sales_history", [])
        ]

    def save(self) -> None:
        data = {
            "employees": [asdict(emp) for emp in self.employees.values()],
            "products": [prod.to_dict() for prod in self.products.values()],
            "sales_history": [sale.to_dict() for sale in self.sales_history],
            "updated_at": _now().isoformat(timespec="seconds"),
        }
        self.path.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")

    def _seed_defaults(self) -> None:
        today = _now().date()
        self.employees = {
            "E001": Employee(
                employee_id="E001",
                name="Li Hua",
                role="Store Manager",
                contact="138-0000-0001",
                base_salary=8000,
                performance_target=120000,
                performance_score=90000,
                guarantor_name="Zhang Wei",
                guarantor_contact="139-0000-0001",
                guarantor_relation="朋友",
            ),
            "E002": Employee(
                employee_id="E002",
                name="Wang Lei",
                role="Sales",
                contact="138-0000-0002",
                base_salary=5000,
                performance_target=80000,
                performance_score=60000,
                guarantor_name="Liu Fang",
                guarantor_contact="139-0000-0002",
                guarantor_relation="亲属",
            ),
        }
        self.products = {
            "S001": Product(
                sku="S001",
                name="Sea Salt 500g",
                category="Salt",
                quantity=150,
                reorder_threshold=50,
                expires_on=datetime(today.year, today.month, today.day) + timedelta(days=90),
                price=25.0,
            ),
            "S002": Product(
                sku="S002",
                name="Sichuan Pepper 200g",
                category="Pepper",
                quantity=40,
                reorder_threshold=30,
                expires_on=datetime(today.year, today.month, today.day) + timedelta(days=25),
                price=35.0,
            ),
        }
        self.save()


class StoreSystem:
    def __init__(self, db: StoreDatabase) -> None:
        self.db = db

    # Employee operations
    def add_employee(
        self,
        employee_id: str,
        name: str,
        role: str,
        contact: str,
        base_salary: float,
        performance_target: float,
        guarantor_name: str = "",
        guarantor_contact: str = "",
        guarantor_relation: str = "",
    ) -> None:
        if employee_id in self.db.employees:
            raise ValueError("Employee ID already exists.")
        self.db.employees[employee_id] = Employee(
            employee_id=employee_id,
            name=name,
            role=role,
            contact=contact,
            base_salary=base_salary,
            performance_target=performance_target,
            guarantor_name=guarantor_name,
            guarantor_contact=guarantor_contact,
            guarantor_relation=guarantor_relation,
        )
        self.db.save()

    def update_employee_info(
        self,
        employee_id: str,
        role: Optional[str] = None,
        contact: Optional[str] = None,
        base_salary: Optional[float] = None,
        performance_target: Optional[float] = None,
        guarantor_name: Optional[str] = None,
        guarantor_contact: Optional[str] = None,
        guarantor_relation: Optional[str] = None,
    ) -> None:
        """更新员工信息"""
        employee = self._get_employee(employee_id)
        if role is not None:
            employee.role = role
        if contact is not None:
            employee.contact = contact
        if base_salary is not None:
            employee.base_salary = base_salary
        if performance_target is not None:
            employee.performance_target = performance_target
        if guarantor_name is not None:
            employee.guarantor_name = guarantor_name
        if guarantor_contact is not None:
            employee.guarantor_contact = guarantor_contact
        if guarantor_relation is not None:
            employee.guarantor_relation = guarantor_relation
        self.db.save()

    def delete_employee(self, employee_id: str) -> None:
        """删除员工"""
        if employee_id not in self.db.employees:
            raise ValueError("Unknown employee ID")
        del self.db.employees[employee_id]
        self.db.save()

    def update_performance(self, employee_id: str, delta: float) -> None:
        employee = self._get_employee(employee_id)
        employee.performance_score += delta
        self.db.save()

    def get_payroll_report(self) -> List[str]:
        report = []
        for emp in self.db.employees.values():
            report.append(
                f"{emp.employee_id} {emp.name} ({emp.role}) | Target: {emp.performance_target:.0f} | "
                f"Score: {emp.performance_score:.0f} | Salary: ¥{emp.salary():.2f}"
            )
        return report

    def _get_employee(self, employee_id: str) -> Employee:
        try:
            return self.db.employees[employee_id]
        except KeyError as exc:
            raise ValueError("Unknown employee ID") from exc

    # Product operations
    def add_product(
        self,
        sku: str,
        name: str,
        category: str,
        quantity: int,
        reorder_threshold: int,
        expires_on: str,
        price: float,
    ) -> None:
        if sku in self.db.products:
            raise ValueError("SKU already exists.")
        product = Product(
            sku=sku,
            name=name,
            category=category,
            quantity=quantity,
            reorder_threshold=reorder_threshold,
            expires_on=_parse_date(expires_on),
            price=price,
        )
        self.db.products[sku] = product
        self.db.save()

    def delete_product(self, sku: str) -> None:
        """删除产品"""
        if sku not in self.db.products:
            raise ValueError("Unknown SKU")
        del self.db.products[sku]
        self.db.save()

    def record_sale(self, sku: str, quantity: int, employee_id: Optional[str] = None) -> None:
        product = self._get_product(sku)
        if quantity <= 0 or quantity > product.quantity:
            raise ValueError("Invalid sale quantity.")
        product.quantity -= quantity
        
        # 记录销售历史，使用产品实际单价
        revenue = quantity * product.price
        sale_id = f"SALE-{_now().strftime('%Y%m%d%H%M%S')}-{len(self.db.sales_history)}"
        sale_record = SaleRecord(
            sale_id=sale_id,
            sku=sku,
            product_name=product.name,
            quantity=quantity,
            employee_id=employee_id,
            sale_date=_now(),
            revenue=revenue,
        )
        self.db.sales_history.append(sale_record)
        
        if employee_id:
            self.update_performance(employee_id, revenue)  # 使用revenue作为绩效增量
        self.db.save()

    def restock(self, sku: str, quantity: int, expires_on: Optional[str] = None, price: Optional[float] = None) -> None:
        """补货产品，可选更新过期日期和单价"""
        product = self._get_product(sku)
        product.quantity += quantity
        if expires_on is not None:
            product.expires_on = _parse_date(expires_on)
        if price is not None:
            product.price = price
        self.db.save()

    def update_product_expiry(self, sku: str, expires_on: str) -> None:
        """更新产品过期日期"""
        product = self._get_product(sku)
        product.expires_on = _parse_date(expires_on)
        self.db.save()

    def _get_product(self, sku: str) -> Product:
        try:
            return self.db.products[sku]
        except KeyError as exc:
            raise ValueError("Unknown SKU") from exc

    # Monitoring and reporting
    def inventory_report(self) -> List[str]:
        lines = []
        for prod in self.db.products.values():
            lines.append(
                f"{prod.sku} {prod.name} | Qty: {prod.quantity} | Reorder <= {prod.reorder_threshold} | "
                f"Expires: {_format_date(prod.expires_on)}"
            )
        return lines

    def expiring_products(self) -> List[str]:
        return [
            f"{prod.sku} {prod.name} expires on {_format_date(prod.expires_on)}"
            for prod in self.db.products.values()
            if prod.needs_expiry_warning()
        ]

    def low_stock_products(self) -> List[str]:
        return [
            f"{prod.sku} {prod.name} current stock {prod.quantity}"
            for prod in self.db.products.values()
            if prod.needs_restock()
        ]

    def get_sales_analysis(self) -> Dict:
        """获取产品销量分析"""
        if not self.db.sales_history:
            return {
                "total_sales": 0,
                "total_revenue": 0.0,
                "by_product": {},
                "by_category": {},
                "by_employee": {},
            }
        
        total_sales = sum(sale.quantity for sale in self.db.sales_history)
        total_revenue = sum(sale.revenue for sale in self.db.sales_history)
        
        by_product: Dict[str, Dict] = {}
        by_category: Dict[str, Dict] = {}
        by_employee: Dict[str, Dict] = {}
        
        for sale in self.db.sales_history:
            # 按产品统计
            if sale.sku not in by_product:
                by_product[sale.sku] = {"name": sale.product_name, "quantity": 0, "revenue": 0.0}
            by_product[sale.sku]["quantity"] += sale.quantity
            by_product[sale.sku]["revenue"] += sale.revenue
            
            # 按类别统计
            product = self.db.products.get(sale.sku)
            if product:
                category = product.category
                if category not in by_category:
                    by_category[category] = {"quantity": 0, "revenue": 0.0}
                by_category[category]["quantity"] += sale.quantity
                by_category[category]["revenue"] += sale.revenue
            
            # 按员工统计
            if sale.employee_id:
                if sale.employee_id not in by_employee:
                    emp = self.db.employees.get(sale.employee_id)
                    by_employee[sale.employee_id] = {
                        "name": emp.name if emp else sale.employee_id,
                        "quantity": 0,
                        "revenue": 0.0,
                    }
                by_employee[sale.employee_id]["quantity"] += sale.quantity
                by_employee[sale.employee_id]["revenue"] += sale.revenue
        
        return {
            "total_sales": total_sales,
            "total_revenue": total_revenue,
            "by_product": by_product,
            "by_category": by_category,
            "by_employee": by_employee,
        }

    def get_employee_quality_analysis(self) -> List[Dict]:
        """获取员工工作质量分析"""
        analysis = []
        sales_by_employee: Dict[str, List[SaleRecord]] = {}
        
        # 按员工分组销售记录
        for sale in self.db.sales_history:
            if sale.employee_id:
                if sale.employee_id not in sales_by_employee:
                    sales_by_employee[sale.employee_id] = []
                sales_by_employee[sale.employee_id].append(sale)
        
        for emp_id, emp in self.db.employees.items():
            sales = sales_by_employee.get(emp_id, [])
            total_sales = len(sales)
            total_revenue = sum(s.revenue for s in sales)
            avg_sale_value = total_revenue / total_sales if total_sales > 0 else 0
            
            # 计算绩效完成率
            completion_rate = (emp.performance_score / emp.performance_target * 100) if emp.performance_target > 0 else 0
            completion_rate = min(completion_rate, 150)  # 最高150%
            
            # 质量评级
            if completion_rate >= 120:
                quality_grade = "优秀"
            elif completion_rate >= 100:
                quality_grade = "良好"
            elif completion_rate >= 80:
                quality_grade = "合格"
            else:
                quality_grade = "待改进"
            
            analysis.append({
                "employee_id": emp_id,
                "name": emp.name,
                "role": emp.role,
                "total_sales": total_sales,
                "total_revenue": total_revenue,
                "avg_sale_value": avg_sale_value,
                "performance_target": emp.performance_target,
                "performance_score": emp.performance_score,
                "completion_rate": round(completion_rate, 2),
                "quality_grade": quality_grade,
                "base_salary": emp.base_salary,
                "actual_salary": emp.salary(),
            })
        
        return sorted(analysis, key=lambda x: x["completion_rate"], reverse=True)

    def get_sales_history(self, limit: int = 100) -> List[SaleRecord]:
        """获取销售历史记录"""
        return sorted(self.db.sales_history, key=lambda x: x.sale_date, reverse=True)[:limit]


def main() -> None:
    db = StoreDatabase(DATA_FILE)
    system = StoreSystem(db)

    menu = {
        "1": ("List employees with payroll", lambda: _print_lines(system.get_payroll_report())),
        "2": ("List inventory", lambda: _print_lines(system.inventory_report())),
        "3": ("Show expiring products", lambda: _print_lines(system.expiring_products(), empty="No upcoming expiries.")),
        "4": ("Show low-stock items", lambda: _print_lines(system.low_stock_products(), empty="All stocks healthy.")),
        "5": ("Add employee", lambda: _cli_add_employee(system)),
        "6": ("Add product", lambda: _cli_add_product(system)),
        "7": ("Record sale", lambda: _cli_record_sale(system)),
        "8": ("Restock product", lambda: _cli_restock(system)),
        "9": ("Update performance", lambda: _cli_update_performance(system)),
        "0": ("Exit", None),
    }

    while True:
        print("\n=== Seasoning Store Management ===")
        for key, (label, _) in menu.items():
            print(f"{key}. {label}")
        choice = input("Select an option: ").strip()
        if choice == "0":
            print("Goodbye!")
            break
        action = menu.get(choice)
        if not action:
            print("Unknown option. Try again.")
            continue
        try:
            action[1]()
        except Exception as exc:  # noqa: BLE001
            print(f"Operation failed: {exc}")


def _print_lines(lines: List[str], empty: str = "No records.") -> None:
    if not lines:
        print(empty)
        return
    for line in lines:
        print(line)


def _cli_add_employee(system: StoreSystem) -> None:
    system.add_employee(
        employee_id=input("Employee ID: ").strip(),
        name=input("Name: ").strip(),
        role=input("Role: ").strip(),
        contact=input("Contact: ").strip(),
        base_salary=float(input("Base salary: ").strip()),
        performance_target=float(input("Performance target: ").strip()),
    )
    print("Employee added.")


def _cli_add_product(system: StoreSystem) -> None:
    system.add_product(
        sku=input("SKU: ").strip(),
        name=input("Name: ").strip(),
        category=input("Category: ").strip(),
        quantity=int(input("Quantity: ").strip()),
        reorder_threshold=int(input("Reorder threshold: ").strip()),
        expires_on=input("Expiry (YYYY-MM-DD): ").strip(),
        price=float(input("Price (default 200): ").strip() or "200"),
    )
    print("Product added.")


def _cli_record_sale(system: StoreSystem) -> None:
    system.record_sale(
        sku=input("SKU: ").strip(),
        quantity=int(input("Sold quantity: ").strip()),
        employee_id=input("Employee ID (optional): ").strip() or None,
    )
    print("Sale recorded.")


def _cli_restock(system: StoreSystem) -> None:
    sku = input("SKU: ").strip()
    quantity = int(input("Restock quantity: ").strip())
    expiry_input = input("Update expiry date (YYYY-MM-DD, optional): ").strip()
    expires_on = expiry_input if expiry_input else None
    price_input = input("Update price (optional): ").strip()
    price = float(price_input) if price_input else None
    system.restock(sku, quantity, expires_on, price)
    updates = []
    if expires_on:
        updates.append("Expiry date updated")
    if price:
        updates.append("Price updated")
    print("Restock completed." + (" " + ", ".join(updates) + "." if updates else ""))


def _cli_update_performance(system: StoreSystem) -> None:
    system.update_performance(
        employee_id=input("Employee ID: ").strip(),
        delta=float(input("Performance delta: ").strip()),
    )
    print("Performance updated.")


if __name__ == "__main__":
    main()

